import os
import numpy as np
import sys
from PyQt5.QtCore import pyqtSignal,pyqtSlot,QThread,QUrl
from PyQt5.QtWidgets import QMainWindow,QApplication,QInputDialog,QFileDialog,\
    QMessageBox,QColorDialog,QListWidgetItem,QTableWidgetItem,QProgressBar,QRadioButton,QMdiSubWindow,QWidget
from PyQt5.QtGui import QCloseEvent,QHideEvent
from PyQt5.QtCore import QTimer
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg
import matplotlib.pyplot as plt
from PyQt5.uic import loadUi
from PyQt5 import QtWebEngineWidgets, QtWebChannel
import folium
from folium.plugins import MousePosition, MeasureControl
from folium.features import CustomIcon
import map4, temjs

import io, re, pandas, json, math
from MapPyQtWeb import MapWebEnginePage, add_customjs
from PIL import Image
import time

class Form(QWidget):

    def getDegreeFromLonLat(self, latA, lonA, latB, lonB):
        """
        Args:
          point p1(latA, lonA)
          point p2(latB, lonB)
        Returns:
          bearing between the two GPS points,
          default: the basis of heading direction is north
        """
        radLatA = math.radians(latA)
        radLonA = math.radians(lonA)
        radLatB = math.radians(latB)
        radLonB = math.radians(lonB)
        dLon = radLonB - radLonA
        y = math.sin(dLon) * math.cos(radLatB)
        x = math.cos(radLatA) * math.sin(radLatB) - math.sin(radLatA) * math.cos(radLatB) * math.cos(dLon)
        brng = math.degrees(math.atan2(y, x))
        brng = (brng + 360) % 360
        return brng

    def handleConsoleMessage(self, msg):
        data = json.loads(msg)
        lat = round(data['coordinates']['lat'], 6)
        lng = round(data['coordinates']['lng'], 6)
        print(f"latitude:{lat} longitude: {lng}")

        if self.Pos_lineEdit.isEnabled():
            self.Pos_lineEdit.setText(f"{lat},{lng}")

        if self.set_traj_checkBox.isChecked() and len(self.trajFromMap) > 1:
            self.traj_checked_pushButton.setEnabled(True)

        if self.set_traj_checkBox.isChecked():
            self.trajFromMap.append([lat, lng])
            if len(self.trajFromMap) > 1:
                self.isetTragFlag = 1
                folium.vector_layers.PolyLine([self.trajFromMap[-2], self.trajFromMap[-1]], popup='设置目标轨迹', tooltip='设置目标轨迹',
                                                  color='blue', weight=2).add_to(self.objtrajgrp)
                self.data = io.BytesIO()
                self.map.save(self.data, close_file=False)
                self.web.setHtml(self.data.getvalue().decode())
        # print("测试")

    def __init__(self):
        super(Form, self).__init__()
        loadUi('folium_hems.ui', self)
        self.web = QtWebEngineWidgets.QWebEngineView()
        self.layoutWeb.addWidget(self.web)

        self.iNumObj = 0
        self.iNumDect = 0
        self.objectsubgrp = []
        self.trajFromMap  = []
        self.object_comboBox.activated[str].connect(self.SetPathOfTraj)

        self.isetTragFlag = 0

        map_latitude = 33.74
        map_longitiude = 129.66

        self.map = folium.Map(
            location=[map_latitude, map_longitiude],
            zoom_start=5,
            zoom_control=True,
            control_scale=True,
            tiles="Stamen Terrain")

        self.map = add_customjs(self.map)
        page = MapWebEnginePage(self)               #在page上增加json功能
        self.web.setPage(page)

        # --------------增加功能插件---------------
        # 点击鼠标左键显示经纬度信息
        click_with_LatLon = folium.LatLngPopup()
        self.map.add_child(click_with_LatLon)

        # 鼠标滑动显示经纬度
        formatter = "function(num) {return L.Util.formatNum(num, 4) + ' º ';};"
        plugin_hover = MousePosition(
            position='topright',
            prefix='经纬度：',
            separator=' | ',
            empty_string='划动显示经纬度',
            lng_first=False,
            num_digits=20,
            lat_formatter=formatter,
            lng_formatter=formatter,
        )
        self.map.add_child(plugin_hover)

        #禁止/开启滚动鼠标放大地图
        plugin_zoom_forbid = folium.plugins.ScrollZoomToggler()
        plugin_zoom_forbid.add_to(self.map)

        # 插件-缩略小地图
        minimap = folium.plugins.MiniMap(toggle_display=True,
                                         tile_layer="Stamen Terrain",
                                         position='bottomright',
                                         width=200, height=150,
                                         zoom_level_offset=-4)
        self.map.add_child(minimap)

        # 插件-通过搜索地名来查找位置
        plugin_geocoder = folium.plugins.Geocoder()
        plugin_geocoder.add_to(self.map)

        # 测量插件
        self.map.add_child(MeasureControl())

        #右键画图插件
        self.map.add_child(temjs.drawcircle())

        #分组显示插件
        self.detectors = folium.FeatureGroup(name = "探测器")
        self.map.add_child(self.detectors)
        self.objects   = folium.FeatureGroup(name = "目标")
        self.map.add_child(self.objects)

        self.objtrajgrp = folium.plugins.FeatureGroupSubGroup(self.objects, name='轨迹设置')
        self.map.add_child(self.objtrajgrp)
        # folium.LayerControl(collapsed=False).add_to(self.map)

        # 画图插件
        plugin_draw = folium.plugins.Draw()
        self.map.add_child(plugin_draw)

        self.data = io.BytesIO()
        self.map.save(self.data, close_file=False)

        self.web.setHtml(self.data.getvalue().decode())
        self.web.show()

    @pyqtSlot()
    def on_layer_pushButton_clicked(self):
        folium.LayerControl(collapsed=False).add_to(self.map)
        self.data = io.BytesIO()
        self.map.save(self.data, close_file = False)
        self.web.setHtml(self.data.getvalue().decode())

    @pyqtSlot()
    def on_reset_pushButton_clicked(self):
        self.web.setHtml(self.data.getvalue().decode())

    @pyqtSlot()
    def on_save_page_pushButton_clicked(self):
        get_filename, ok = QFileDialog.getSaveFileName(self, "Save map to html file", "", "Html Files (*.html)")
        if ok:
            self.map.save(get_filename)

    @pyqtSlot()
    def on_load_pushButton_clicked(self):
        get_filename_path, ok = QFileDialog.getOpenFileName(self,
                                    "选取单个文件",
                                    "C:/",
                                    "All Files (*);;Html Files (*.html)")
        if ok:
            self.web.load(QUrl.fromLocalFile(get_filename_path))

    def SetPathOfTraj(self, str_temp):
        items = ['plane', 'ship', 'launcher']
        if str_temp in items:
           self.traj_lineEdit.setEnabled(True)
           self.traj_pushButton.setEnabled(True)
        else:
           self.traj_lineEdit.setEnabled(False)
           self.traj_pushButton.setEnabled(False)

    @pyqtSlot()
    def on_traj_pushButton_clicked(self):
        get_filename_path, ok = QFileDialog.getOpenFileName(self,
                                    "选取单个文件",
                                    "C:/",
                                    "All Files (*);;Text Files (*.csv)")
        if ok:
            self.traj_lineEdit.setText(get_filename_path)

    @pyqtSlot()
    def on_traj_checked_pushButton_clicked(self):
        self.set_traj_checkBox.setChecked(False)
        self.traj_checked_pushButton.setEnabled(False)
        self.traj_lineEdit.setEnabled(False)
        self.traj_pushButton.setEnabled(False)
        # self.trajFromMap.clear()

    @pyqtSlot()
    def on_set_traj_checkBox_clicked(self):
        if self.set_traj_checkBox.isChecked():
            self.traj_lineEdit.setEnabled(False)
            self.traj_pushButton.setEnabled(False)
            if len(self.trajFromMap) > 1:
                self.traj_checked_pushButton.setEnabled(True)
        else:
            self.traj_lineEdit.setEnabled(True)
            self.traj_pushButton.setEnabled(True)

    @pyqtSlot()
    def on_init_pos_checkBox_clicked(self):
        if self.init_pos_checkBox.isChecked():
            self.Pos_lineEdit.setEnabled(False)
        else:
            self.Pos_lineEdit.setEnabled(True)

    @pyqtSlot()
    def on_add_obj_pushButton_clicked(self):
        items = ['plane', 'ship', 'launcher']
        radar = "radar.png"

        # image_temp = Image.open(radar)
        # image_temp.rotate(45).save(radar)

        radar_iconSize = (40, 40)
        plane = "f22.png"
        plane_iconSize = (40, 50)
        ship  = "ship.png"
        ship_iconSize  = (40, 70)
        launcher = 'launcher.png'
        launcher_iconSize = (50, 40)

        index_temp = self.object_comboBox.currentIndex()
        if index_temp == 0:
            QMessageBox.information(self, "提示", "请选择要添加的目标！")
            return

        object_name = self.object_comboBox.currentText()
        icon = CustomIcon(
            eval(object_name),
            icon_size=eval(object_name + '_iconSize'),
            icon_anchor = (10, 10),
            popup_anchor= ( 0,  0),
        )

        if not self.init_pos_checkBox.isChecked():
            latitude    = re.split('，|,| ', self.Pos_lineEdit.text())[0]
            longitiude  = re.split('，|,| ', self.Pos_lineEdit.text())[1]

            marker = map4.Marker(
                location = [latitude, longitiude],
                icon  = icon,
                popup = self.obj_info_textEdit.toPlainText(),
                tooltip = object_name,
                draggable=True,
            )
        Plain_text  = re.split('，|,| ', self.obj_info_textEdit.toPlainText())

        iNameObjFlg = 0
        if self.object_comboBox.currentText() in items:     #对目标对象做特殊处理

            self.iNumObj += 1
            for str_temp in Plain_text:
                if "名称" in str_temp:
                    iNameObjFlg = 1
                    iPos = str_temp.rfind("名称")
                    sNameObj = str_temp[iPos+3:]
            if iNameObjFlg == 0 :
                sNameObj = self.object_comboBox.currentText() + str(self.iNumObj)

            # 构建一个子组队列
            self.objectsubgrp.append(folium.plugins.FeatureGroupSubGroup(self.objects, name=sNameObj))
            self.map.add_child(self.objectsubgrp[-1])

            if self.isetTragFlag:
                self.trajectory = self.trajFromMap
            else:
                # 读取目标的轨迹并画线  %调试
                if self.traj_lineEdit.isEnabled() and self.traj_lineEdit.text() != '':
                    file_extension = os.path.splitext(self.traj_lineEdit.text())[-1]

                    if file_extension == '.csv':
                        self.trajectory = pandas.read_csv(self.traj_lineEdit.text(), header=0, names=["纬度", "经度"], encoding='gbk')
                        self.trajectory = self.trajectory.values
                    elif file_extension in ['.xls', '.xlsx']:
                        self.trajectory = pandas.read_excel(self.traj_lineEdit.text(), header=0, names=["纬度", "经度"])
                        self.trajectory = self.trajectory.values
                    else:
                        QMessageBox.information(self, "提示","没有找到指定的轨迹文件，将生成系统默认轨迹")
                        self.trajectory = [[-1.47, -5.56],  [-1.27, -5.29], [-0.878, -5.34], [-0.417, -5.317], [0.088, -5.49],
                                      [0.703, -5.625], [1.34, -5.887], [1.713, -5.97], [2.153, -6.219], [2.39, -6.17],\
                                      [2.78, -6.19]]
                else:
                    QMessageBox.information(self, "提示", "没有指定目标轨迹，将生成系统默认轨迹")
                    self.trajectory = [[-1.47, -5.56], [-1.27, -5.29], [-0.878, -5.34], [-0.417, -5.317], [0.088, -5.49], [0.703, -5.625],\
                                  [1.34, -5.887], [1.713, -5.97], [2.153, -6.219], [2.39, -6.17], [2.78, -6.19]]
                # line_1 = folium.vector_layers.PolyLine(trajectory, popup='<b>Path of {}</b>'.format(sNameObj), tooltip=sNameObj,
                #                                        color='blue', weight=3).add_to(self.objectsubgrp[-1])

            latitude = self.trajectory[0][0]
            longitiude = self.trajectory[0][1]
            fDegree = self.getDegreeFromLonLat(self.trajectory[0][0], self.trajectory[0][1], self.trajectory[1][0], self.trajectory[1][1])
            image_temp = Image.open(eval(object_name))
            image_temp.rotate(-fDegree, expand=True).save('./temp.png')

            icon = CustomIcon(
                './temp.png',
                icon_size =eval(object_name + '_iconSize'),
                icon_anchor  = (10, 10),
                popup_anchor = (0, 0),
            )
            marker  = map4.Marker(
                location=[latitude, longitiude],
                icon=icon,
                popup=self.obj_info_textEdit.toPlainText(),
                tooltip=object_name,
                draggable=True,
            ).add_to(self.objectsubgrp[-1])     #在初始位置加一个目标Icon

            # self.objectsubgrp[-1].add_child(marker)         #将目标图标加载到特征子组中
            # # 生成静态的蚁行图
            folium.plugins.AntPath(locations=self.trajectory, dash_array=[10, 20], tooltip=sNameObj,).add_to(self.objectsubgrp[-1])


            # 考虑生成动态的图, 动态图有bug 暂时无法解决
            # import datetime
            # iTimeInit = datetime.datetime.now().timestamp()
            # iTimeEnd  = iTimeInit + 86400       #时间戳加1天
            # iTimeInit *= 1000                   #转换为json中的时间戳
            # iTimeEnd  *= 1000
            # timestramp_list = np.linspace(iTimeInit, iTimeEnd, len(self.trajectory), endpoint=True).tolist()
            #
            # for index , iList in enumerate(self.trajectory):
            #     self.trajectory[index]= [iList[1], iList[0]]
            # line_2 = {
            #     'type': 'Feature',
            #     'geometry': {
            #         'type': 'LineString',
            #         'coordinates': self.trajectory,
            #     },
            #     'properties':
            #         {
            #             'style': {
            #                 'color': 'blue',
            #             },
            #             'icon': 'marker',
            #             # 'iconstyle': {'iconUrl':'f22.png', 'iconSize': (30, 30),},
            #             'times': timestramp_list,
            #         }
            # }
            # folium.plugins.TimestampedGeoJson({
            #     'type': 'FeatureCollection',
            #     'features': [line_2],
            #     },
            #     period='PT1H',
            #     duration=None).add_to(self.map)

        else:   #设置探测器对象
            self.detectors.add_child(marker)
            self.iNumDect += 1

            # 扇形势力区域插件
            iCoverRFlag = 0
            iStartAngFlag = 0
            iEndAngFlag = 0
            for str_temp in Plain_text:
                if "名称" in str_temp:
                    iNameObjFlg = 1
                    iPos =str_temp.rfind("名称")
                    sNameObj = str_temp[iPos+3:]
                if "覆盖半径" in str_temp or "探测距离" in str_temp:
                    if str_temp.rfind('km') != -1:
                        iCoverRFlag = 1
                        fRdius_object = float("".join(list(filter(str.isdigit, str_temp))))*1000.0
                    elif str_temp.rfind('m') != -1:
                        iCoverRFlag = 1
                        fRdius_object = float("".join(list(filter(str.isdigit, str_temp))))
                    else:
                        QMessageBox.information(self, '提示','对象的覆盖半径描述中没有给出单位，应明确是m还是km')
                        return
                if "起始角度" in str_temp:
                    iStartAngFlag = 1
                    f_angle_start = float("".join(list(filter(str.isdigit, str_temp))))
                if "终止角度" in str_temp:
                    iEndAngFlag = 1
                    f_angle_end = float("".join(list(filter(str.isdigit, str_temp))))

            if iNameObjFlg == 0:
                fNameObj = self.object_comboBox.currentText() + str(self.iNumDect)
            if iStartAngFlag == 0:
                f_angle_start = 0.0     #设置默认值
                iStartAngFlag = 1
            if iEndAngFlag == 0:
                f_angle_end = 0.0
                iEndAngFlag = 1
            if iCoverRFlag and iStartAngFlag and iEndAngFlag:
                folium.plugins.SemiCircle(
                    (latitude, longitiude),
                    radius = fRdius_object,
                    start_angle = f_angle_start,
                    stop_angle = f_angle_end,
                    color = "red",
                    fill_color = "red",
                    opacity = 0.1,
                    popup = f"start angle - {f_angle_start} degrees, stop angle - {f_angle_end} degrees",
                    tooltip ='覆盖区域'
                ).add_to(self.detectors)

        self.data = io.BytesIO()
        self.map.save(self.data, close_file = False)
        self.web.setHtml(self.data.getvalue().decode())

        self.isetTragFlag = 0
        self.trajFromMap.clear()
        self.traj_lineEdit.setEnabled(False)        #reset
        self.traj_pushButton.setEnabled(False)

if __name__ == "__main__":
    app = QApplication(sys.argv)
    form = Form()
    form.show()
    sys.exit(app.exec_())